package com.gin.fanbox.client;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gin.fanbox.call.FanboxCall;
import lombok.Getter;
import okhttp3.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.net.InetSocketAddress;
import java.net.Proxy;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Fanbox请求客户端
 *
 * @author bx002
 * @since 2024/2/5 11:30
 */
@Getter
public class FanboxClient {
    public static final String SESSION_ID_REGEXP = "^(\\d+)_.{32}$";
    /**
     * session id 的格式
     */
    public static final Pattern SESSION_ID_PATTERN = Pattern.compile(SESSION_ID_REGEXP);
    public static final String SESSION_ID_KEY = "FANBOXSESSID";
    /**
     * Header中的Referer字段
     */
    public static final String REFERER = "https://www.fanbox.cc";
    private final String cookie;
    private final OkHttpClient okHttpClient;

    public FanboxClient(@NotNull String sessionId) {
        this(sessionId, null);
    }

    public FanboxClient(@NotNull String sessionId, @Nullable OkHttpClient okHttpClient) {
        final Matcher matcher = SESSION_ID_PATTERN.matcher(sessionId);
        if (!matcher.find()) {
            throw new RuntimeException("session id 格式错误, 应当为 '{数字}_{32位字符}'");
        }

        this.cookie = String.format("%s=%s;", SESSION_ID_KEY, sessionId);
        this.okHttpClient = okHttpClient != null ? okHttpClient : defualtOkHttpClient();
    }


    /**
     * 生成URL的方法
     *
     * @param pathSegment     路径
     * @param queryParameters 查询参数
     * @return url
     */
    public HttpUrl obtainHttpUrl(@NotNull String pathSegment, @Nullable Map<String, String> queryParameters) {
        final HttpUrl.Builder builder = new HttpUrl.Builder()
                .scheme("https")
                .host("api.fanbox.cc")
                .addPathSegment(pathSegment);

        if (queryParameters != null) {
            for (Map.Entry<String, String> entry : queryParameters.entrySet()) {
                if (entry.getValue() != null && !entry.getValue().isEmpty()) {
                    builder.addQueryParameter(entry.getKey(), entry.getValue());
                }
            }
        }
        return builder.build();
    }

    /**
     * 生成请求
     *
     * @param httpUrl     url
     * @param method      请求方法： get post
     * @param requestBody 请求体
     * @return 请求
     */
    public Request obtainRequest(@NotNull HttpUrl httpUrl, @NotNull String method, @Nullable RequestBody requestBody) {
        return new Request.Builder()
                .url(httpUrl)
                .header("Origin", REFERER)
                .header("referer", REFERER)
                .header("cookie", cookie)
                .method(method.toUpperCase(), requestBody)
                .build();
    }

    public Call call(@NotNull String pathSegments, @Nullable Object queryParameters) {

        final ObjectMapper mapper = new ObjectMapper();
        HashMap<String, String> map;
        try {
            map = mapper.readValue(mapper.writeValueAsString(queryParameters), new TypeReference<HashMap<String, String>>() {
            });
        } catch (JsonProcessingException e) {
            map = new HashMap<>();
        }

        return call(pathSegments, "GET", map, null);
    }

    public <T> FanboxCall<T> call(
            @NotNull String pathSegments, @NotNull Class<T> responseClass, @NotNull String key, @NotNull String value) {
        final HashMap<String, String> queryParameters = new HashMap<>();
        queryParameters.put(key, value);
        final Call call = call(pathSegments, queryParameters);
        return new FanboxCall<>(call, responseClass);
    }

    public <T> FanboxCall<T> call(
            @NotNull String pathSegments, @NotNull Class<T> responseClass, @Nullable Object queryParameters) {
        final Call call = call(pathSegments, queryParameters);
        return new FanboxCall<>(call, responseClass);
    }

    public Call call(@NotNull String pathSegments, @Nullable Map<String, String> queryParameters) {
        return call(pathSegments, "GET", queryParameters, null);
    }

    public Call call(
            @NotNull String pathSegments,
            @NotNull String method, @Nullable Map<String, String> queryParameters, @Nullable RequestBody requestBody) {
        final HttpUrl httpUrl = obtainHttpUrl(pathSegments, queryParameters);
        final Request request = obtainRequest(httpUrl, method, requestBody);
        return okHttpClient.newCall(request);
    }


    /**
     * 默认使用的客户端
     *
     * @return 客户端
     */
    @NotNull
    public static OkHttpClient defualtOkHttpClient() {
        return new OkHttpClient.Builder()
                .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", 10809)))
                .readTimeout(30, TimeUnit.SECONDS)
                .callTimeout(30, TimeUnit.SECONDS)
                .connectTimeout(30, TimeUnit.SECONDS).build();
    }
}
